package com.investmenttechnologyservices.services;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Logger;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Link;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
import com.google.appengine.api.datastore.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.datastore.Transaction;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.inject.Inject;
import com.google.inject.Stage;
import com.investmenttechnologyservices.model.Account;
import com.investmenttechnologyservices.model.Bank;
import com.investmenttechnologyservices.model.Broker;
import com.investmenttechnologyservices.model.Firm;
import com.investmenttechnologyservices.model.HolidayDate;
import com.investmenttechnologyservices.model.Position;
import com.investmenttechnologyservices.model.PriceFormat;
import com.investmenttechnologyservices.model.QuoteRTListed;
import com.investmenttechnologyservices.model.Region;
import com.investmenttechnologyservices.model.StageType;
import com.investmenttechnologyservices.model.Trade;
import com.investmenttechnologyservices.model.UserITS;
import com.investmenttechnologyservices.util.DateUtil;
import com.investmenttechnologyservices.util.YahooRealTimeQuoteLoader;

public class EntityTestService {
	
	private static final Logger log = Logger.getLogger(EntityTestService.class.getName());

	private final DatastoreService ds;
	private final UserService userService;
	private final TradeService tradeService;
	private final PositionService positionService;

	@Inject
	private EntityTestService(DatastoreService ds, UserService userService,
			TradeService tradeService, PositionService positionService,
			HolidayDateService holidayDateService, InstrumentService instrumentService) {
		this.ds = ds;
		this.userService = userService;
		this.tradeService = tradeService;
		this.positionService = positionService;
	}

	public void testEntity() {

		// Step 1: create the firm
		// For individuals or first user of a firm, first create the firm and then the user
		// 

		Transaction tx = ds.beginTransaction();

		Firm myFirm = new Firm("My test Firm");
		ds.put(myFirm.asEntity());

		Key firmKey = myFirm.getKey();

		tx.commit();		

		tx = ds.beginTransaction();

		User user = userService.getCurrentUser();
		String userId = user.getUserId().toString();
		
		UserITS userITS = new UserITS(userId, "David Goodman", firmKey);
		
		ds.put(userITS.asEntity());
		tx.commit();		

		tx = ds.beginTransaction();

		Region world = new Region("world", "World");
		ds.put(world.asEntity());
		tx.commit();		

		tx = ds.beginTransaction();
		
		Region na = new Region("na", "North America", world.getKey());
		ds.put(na.asEntity());
		tx.commit();		

		tx = ds.beginTransaction();
		
		Region us = new Region("us", "US of A", na.getKey());
		ds.put(us.asEntity());
		tx.commit();		
		
		

		Query q = new Query("holidayDate");
		PreparedQuery pq = ds.prepare(q);
		Iterable<Entity> iter = pq.asIterable();
		for (Entity entity : iter) {
			tx = ds.beginTransaction();
			ds.delete(entity.getKey());
			tx.commit();
		}

		// add holidays
		tx = ds.beginTransaction();
		ds.put(new HolidayDate(na.getKey(), DateUtil.createDateUTC(2000,1,1)).asEntity());
		tx.commit();		
		tx = ds.beginTransaction();
		ds.put(new HolidayDate(na.getKey(), DateUtil.createDateUTC(2000,12,25)).asEntity());
		tx.commit();		
		tx = ds.beginTransaction();
		ds.put(new HolidayDate(na.getKey(), DateUtil.createDateUTC(2012,9,3),false,false).asEntity());
		tx.commit();		
		tx = ds.beginTransaction();
		ds.put(new HolidayDate(na.getKey(), DateUtil.createDateUTC(2013,9,2),false,false).asEntity());
		tx.commit();		
		
		tx = ds.beginTransaction();
		
		Link bankUrl = null;
		Bank bank = new Bank("BofA", "Bank of America", "BofA", "BofA", bankUrl, "", na.getKey());

		ds.put(bank.asEntity());
		tx.commit();
		
		Set<String> defaultTags = new HashSet<String>();
		defaultTags.add("Tag1");
		defaultTags.add("Tag2");

		List<Entity> accounts = new ArrayList<Entity>();
		accounts.add(new Account("Account 1","","Account1", "", firmKey, null, null, defaultTags).asEntity());
		accounts.add(new Account("Account 2","","Account2", "", firmKey, null, null, defaultTags).asEntity());
		accounts.add(new Account("Account 3","","Account3", "", firmKey, null, null, defaultTags).asEntity());
		accounts.add(new Account("Account 4","","Account4", "", firmKey, null, null, defaultTags).asEntity());
		accounts.add(new Account("Account 5","","Account5", "", firmKey, null, null, defaultTags).asEntity());

		// clear trades in accounts
		Integer i;
		for (i=0;i<5;i++) {
			tx = ds.beginTransaction();
			q = new Query("trade").setAncestor(firmKey);
			pq = ds.prepare(q);
			iter = pq.asIterable();
			for (Entity entity : iter) {
				ds.delete(entity.getKey());
			}
			tx.commit();
		}
		
		// clear accounts
		q = new Query("account").setAncestor(firmKey);
		pq = ds.prepare(q);
		iter = pq.asIterable();
		for (Entity entity : iter) {
			tx = ds.beginTransaction();
			ds.delete(entity.getKey());
			tx.commit();
		}
		
		// save new accounts
		tx = ds.beginTransaction();
		ds.put(accounts);
		tx.commit();		
		
		tx = ds.beginTransaction();

		Broker myBroker = new Broker("test1",firmKey,"Goodman brokerage", 
				"Goodman Borkerage seriously log name");
		ds.put(myBroker.asEntity());
		tx.commit();

		q = new Query("symbol");
		pq = ds.prepare(q);
		iter = pq.asIterable();
		List<Key> ret = new ArrayList<Key>();
		for (Entity entity : iter) {
			ret.add(entity.getKey());
		}
		Integer numberOfSymbols = ret.size();

	    Random r = new Random();
	    
	    Integer j,k,days,bd,symbol;
	    Double quantity, price;
		Set<String> tradeTags;
		Date tradeDate;
		Integer count = 50;
		Integer countAccounts = 5; // max 5
		
		String instrumentId, symbolId;
		Long accountId;
		
	    for (i=0;i<count;i++) {
	    	r				= new Random();
	    	quantity 		= Math.round(r.nextDouble() * 300.0)*10.0;
	    	price 			= Math.round(r.nextDouble() * 1500000.0)/10000.0;
	    	j 				= r.nextInt(countAccounts);
	    	k				= r.nextInt(5);
	    	days			= r.nextInt(60);
	    	bd				= r.nextInt(2);
	    	symbol 			= r.nextInt(numberOfSymbols);
	    	
	    	tradeTags		= new HashSet<String>();
    		tradeDate		= DateUtil.nextWeekDay(62L, DateUtil.addDays(new Date(),-days));
	    	
	    	symbolId		= ret.get(symbol).getName();
	    	instrumentId	= ret.get(symbol).getParent().getName();
	    	accountId		= accounts.get(j).getKey().getId();
	    	
	    	if (k>1) 
	    		tradeTags.add("Tag"+k.toString());
    		tradeService.initTrade(instrumentId, symbolId, accountId, quantity,
   				price, tradeDate, new ArrayList<String>(tradeTags),
   				(bd==0)?StageType.ORDER:StageType.TRANSACTION);
    		
	    }
	    	
    	i	= r.nextInt(count);
    	quantity = Math.round(r.nextDouble() * 300.0)*10.0;
	}

	public void showPositions() {
		List<Position> positions = new ArrayList<Position>();

		FetchOptions fo = FetchOptions.Builder.withDefaults();

		Query q = new Query("firm").setKeysOnly();
		List<Entity> result = ds.prepare(q).asList(fo);
		if (result.size()>1) {
			System.err.println("Can't find firm - exiting!!!");
			return;
		}
		Key firmKey = result.get(0).getKey();

		q = new Query("account").setAncestor(firmKey);
		List<Entity> accounts= ds.prepare(q).asList(fo);
		int countAccounts= accounts.size();

		int j;
		for (j=0; j<countAccounts; j++) {
			positions = positionService.getCurrentAccountPositions(accounts.get(j).getKey());
			System.err.println("Number of positions queried: "+positions.size());
			Iterator<Position> iterator = positions.iterator();
			while (iterator.hasNext()) {
				System.err.println(iterator.next().toString());
			}
		}

	}
	
	public void testTrades() {

		FetchOptions fo = FetchOptions.Builder.withDefaults();

		Query q = new Query("firm").setKeysOnly();
		List<Entity> result = ds.prepare(q).asList(fo);
		if (result.size()>1) {
			System.err.println("Can't find firm - exiting!!!");
			return;
		}
		Key firmKey = result.get(0).getKey();

		q = new Query("symbol");
		PreparedQuery pq = ds.prepare(q);
		Iterable<Entity> iter = pq.asIterable();
		List<Key> ret = new ArrayList<Key>();
		for (Entity entity : iter) {
			ret.add(entity.getKey());
		}
		Integer numberOfSymbols = ret.size();

		
		String instrumentId, symbolId;
		Long accountId;

		Integer i;
	    Integer j,k,symbol;
	    Double quantity, price;
		Trade newTrade = null;
		Integer count = 1;
		Integer countAccounts = 0;
		
		Key regionKey = KeyFactory.createKey("region", "na");
		
		q = new Query("account").setAncestor(firmKey);
		List<Entity> accounts= ds.prepare(q).asList(fo);
		Map<Key,List<Entity>> accountTrades = new HashMap<Key,List<Entity>>();
		List<Entity> trades = new ArrayList<Entity>();
		for (Entity entity: accounts) {
			accountTrades.put(entity.getKey(),trades);
			countAccounts++;
		}

		Random r = new Random();
		
    	i				= r.nextInt(count);
    	quantity 		= Math.round(r.nextDouble() * 300.0)*10.0;
    	price 			= Math.round(r.nextDouble() * 1500000.0)/10000.0;
    	j 				= r.nextInt(countAccounts);
    	k				= r.nextInt(5);
    	symbol 			= r.nextInt(numberOfSymbols);
    	quantity = Math.round(r.nextDouble() * 300.0)*10.0;
    	

		Key accountKey = accounts.get(j).getKey();

		trades = accountTrades.get(accountKey);
		if (trades.isEmpty()) {
			Filter tradeExpirationFilter = 
					new FilterPredicate("expirationTimestamp",FilterOperator.EQUAL,null);
			Filter tradeStageTypeFilter = CompositeFilterOperator.or(
						new FilterPredicate("stageType",FilterOperator.EQUAL,StageType.ORDER.name()),
						new FilterPredicate("stageType",FilterOperator.EQUAL,StageType.EXECUTION.name()),
						new FilterPredicate("stageType",FilterOperator.EQUAL,StageType.TRANSACTION.name()));
			Filter noCash = new FilterPredicate("instrumentTradeKey",FilterOperator.EQUAL,null);
			Filter notActiveFilter =
					CompositeFilterOperator.and(tradeExpirationFilter,tradeStageTypeFilter,noCash);
			q = new Query ("trade").setFilter(notActiveFilter)
					.setAncestor(accountKey)
					.addSort("effectiveTimestamp", SortDirection.DESCENDING);
			trades = ds.prepare(q).asList(fo);
			accountTrades.put(accountKey,trades);
		}
		log.info("[testTrades: trades found="+trades.size()+"]");
		try {
			count = trades.size();
			i = r.nextInt(count);
			//Make a change to the trade
			log.info("\n\n\n[****Change trade quantity.]\n\n\n");
			Entity entity = trades.get(i);
			Trade trade = new Trade(entity);
			log.info("[testTrades: trade="+trade.toString());
			Long tradeId = trade.getTradeId();
			tradeService.modifyTrade(
				entity.getKey(), 
				Math.round(trade.getQuantity()*0.0083)*100.0, 
				trade.getQuotePrice(),
   				trade.getTradeDate(), 
   				trade.getTags());
			log.info("[****After:]");
			listByTradeId(trade.getKey().getParent(), tradeId);
			
			// Cancel a trade
			log.info("\n\n\n[****Cancel a trade.]\n\n\n");
	    	i	= r.nextInt(count);
			//Make a change to the trade
			entity = trades.get(i);
			trade = new Trade(entity);
			tradeId = trade.getTradeId();
			log.info("[****Before:]");
			listByTradeId(trade.getKey().getParent(), tradeId);
			tradeService.cancelTrade(entity.getKey()); 
			log.info("[****After:]");
			listByTradeId(trade.getKey().getParent(), tradeId);
			
	
			// 
			log.info("\n\n\n[****Create order. Execute 2/3 and then execute 1/3.]\n\n\n");
	    	symbol 		= r.nextInt(numberOfSymbols);
	    	j			= 1;
	    	price 		= Math.round(r.nextDouble() * 1500000.0)/10000.0;
	    	int days	= r.nextInt(30);

	    	symbolId		= ret.get(symbol).getName();
	    	instrumentId	= ret.get(symbol).getParent().getName();
	    	accountId		= accounts.get(j).getKey().getId();
	    	accountKey		= accounts.get(j).getKey();

	    	quantity 		= Math.round(r.nextDouble() * 300.0)*10.0;
	    	price 			= Math.round(r.nextDouble() * 1500000.0)/10000.0;
	    	symbol 		= r.nextInt(numberOfSymbols);
	    	j			= 1;
	    	price 		= Math.round(r.nextDouble() * 1500000.0)/10000.0;
	    	days	= r.nextInt(30);

	    	symbolId		= ret.get(symbol).getName();
	    	instrumentId	= ret.get(symbol).getParent().getName();
	    	accountId		= accounts.get(j).getKey().getId();
	    	accountKey		= accounts.get(j).getKey();

	    	quantity 		= Math.round(r.nextDouble() * 300.0)*10.0;
	    	price 			= Math.round(r.nextDouble() * 1500000.0)/10000.0;

    		Date tradeDate	= DateUtil.nextWeekDay(62L, DateUtil.addDays(new Date(),-days));

    		tradeService.createNewTrade(instrumentId, symbolId, accountId, quantity,
	    			price, null, null, StageType.ORDER);
	    	
			Filter tradeExpirationFilter = 
					new FilterPredicate("expirationTimestamp",FilterOperator.EQUAL,null);
			Filter tradeStageTypeFilter = 
						new FilterPredicate("stageType",FilterOperator.EQUAL,StageType.ORDER.name());
			Filter symbolFilter = 
					new FilterPredicate("symbolKey",FilterOperator.EQUAL,ret.get(symbol));
			Filter notActiveFilter =
					CompositeFilterOperator.and(tradeExpirationFilter,tradeStageTypeFilter, symbolFilter);
			q = new Query ("trade").setFilter(notActiveFilter)
					.setAncestor(accountKey)
					.addSort("effectiveTimestamp", SortDirection.DESCENDING);
			trades = ds.prepare(q).asList(fo);

			Key tradeKey;
			
			if (!trades.isEmpty()) {
				entity = trades.get(0);
				tradeKey = entity.getKey();
				trade = new Trade(entity);
				tradeId = trade.getTradeId();
				log.info("\n\n\n[****Before:]");
				listByTradeId(accountKey, tradeId);
				tradeService.modifyTrade(
					tradeKey, 
					Math.round(trade.getQuantity()*0.0067)*100.0, 
					trade.getQuotePrice(),
	   				trade.getTradeDate(), 
	   				trade.getTags());
				log.info("\n\n\n[****After:]");
				listByTradeId(accountKey, tradeId);
				try {
					Thread.sleep(3000);
				} catch (InterruptedException ex) {
					// TODO Auto-generated catch block
					ex.printStackTrace();
				}
				log.info("\n\n\n[****Before:]");
				listByTradeId(accountKey, tradeId);
				tradeService.modifyTrade(
						tradeKey, 
						Math.round(trade.getQuantity()*0.0033)*100.0, 
						trade.getQuotePrice(),
		   				trade.getTradeDate(), 
		   				trade.getTags());
				log.info("\n\n\n[****After:]");
				listByTradeId(accountKey, tradeId);
			}

			
			try {
				Thread.sleep(3000);
			} catch (InterruptedException ex) {
				// TODO Auto-generated catch block
				ex.printStackTrace();
			}

			log.info("\n\n\n[****Create order. Change order to 1/2. Execute fully. Correct to execute 1/2.]\n\n\n");
	    	symbol 		= r.nextInt(numberOfSymbols);
	    	j			= 1;
	    
	    	symbolId		= ret.get(symbol).getName();
	    	instrumentId	= ret.get(symbol).getParent().getName();
	    	accountId		= accounts.get(j).getKey().getId();
	    	accountKey		= accounts.get(j).getKey();

	    	quantity 		= Math.round(r.nextDouble() * 300.0)*10.0;
	    	price 			= Math.round(r.nextDouble() * 1500000.0)/10000.0;

    		tradeDate	= DateUtil.nextWeekDay(62L, DateUtil.addDays(new Date(),-days));
	    	tradeService.createNewTrade(instrumentId, symbolId, accountId, quantity,
	    			price, null, null, StageType.ORDER);

	    	Filter cashFilter = 
	    		new FilterPredicate("instrumentTradeKey",FilterOperator.EQUAL,null);
			tradeExpirationFilter = 
				new FilterPredicate("expirationTimestamp",FilterOperator.EQUAL,null);
			tradeStageTypeFilter = 
				new FilterPredicate("stageType",FilterOperator.EQUAL,StageType.ORDER.name());
			Filter tradeSymbolFilter = 
					new FilterPredicate("symbolKey",FilterOperator.EQUAL,ret.get(symbol));
			notActiveFilter =
				CompositeFilterOperator.and(tradeExpirationFilter,cashFilter, tradeStageTypeFilter, tradeSymbolFilter);
			q = new Query ("trade").setFilter(notActiveFilter)
					.setAncestor(accountKey)
					.addSort("effectiveTimestamp", SortDirection.DESCENDING);
			trades = ds.prepare(q).asList(fo);
	
			// change the order by half
			if (!trades.isEmpty()) {
				newTrade = new Trade(trades.get(0));
				tradeId = newTrade.getTradeId();
				tradeService.modifyTrade(trades.get(0).getKey(), 
						newTrade.getQuantity()/2.0, 
						null, null, null);
				log.info("[****After: order change]");
				listByTradeId(accountKey, tradeId);

				tradeService.executeOrder(trades.get(0).getKey(), 
						newTrade.getQuantity()/2.0, 
						Math.round(r.nextDouble() * 1500000.0)/10000.0, 
						new Date());
				log.info("[****After: full execution]");
				listByTradeId(accountKey, tradeId);

				tradeStageTypeFilter = 
					new FilterPredicate("stageType",FilterOperator.EQUAL,StageType.TRANSACTION.name());
				notActiveFilter =
						CompositeFilterOperator.and(tradeExpirationFilter, cashFilter, tradeStageTypeFilter, tradeSymbolFilter);
				q = new Query ("trade").setFilter(notActiveFilter)
						.setAncestor(accountKey)
						.addSort("effectiveTimestamp", SortDirection.DESCENDING);
				trades = ds.prepare(q).asList(fo);

				if (trades.isEmpty())
					log.info("transaction not found!");
				else {
					newTrade = new Trade(trades.get(0));
					tradeId = newTrade.getTradeId();
					tradeService.modifyTrade(trades.get(0).getKey(), 
							newTrade.getQuantity()/2.0, 
							null, null, null);
					log.info("[****After: order change]");
					listByTradeId(accountKey, tradeId);
					
				}
			
			} else {
				log.info("order not listed!!");
			}
			
		}
		catch(IllegalArgumentException ex) {
			ex.printStackTrace();
		}
	}

	public void positionsValuedwithYahooQuotes() {
		
		FetchOptions fo = FetchOptions.Builder.withDefaults();

		Query q = new Query("firm").setKeysOnly();
		List<Entity> result = ds.prepare(q).asList(fo);
		if (result.size()>1) {
			System.err.println("Can't find firm - exiting!!!");
			return;
		}
		Key firmKey = result.get(0).getKey();

		Integer countAccounts = 0;
		
		q = new Query("account").setAncestor(firmKey);
		List<Entity> accounts= ds.prepare(q).asList(fo);
		Map<Key,List<Entity>> accountTrades = new HashMap<Key,List<Entity>>();
		List<Entity> trades = new ArrayList<Entity>();
		for (Entity entity: accounts) {
			accountTrades.put(entity.getKey(),trades);
			countAccounts++;
		}
		
		List<Position> positions = new ArrayList<Position>();

		Random r = new Random();
		Integer j = r.nextInt(countAccounts);
		
		positions = positionService.getCurrentAccountPositions(accounts.get(j).getKey());
		System.err.println("Number of positions queried: "+positions.size());
		
		Set<String> symbols = new HashSet<String>();
		Map<String,Double> quoteMap = new HashMap<String,Double>();
		
		Iterator<Position> iterator = positions.iterator();
		Position position;
		String stringUrl;
		QuoteRTListed quoteRTListed; 
		while (iterator.hasNext()) {
			position = iterator.next();
			log.info(position.toString());
			symbols.add(position.getSymbolKey().getName().trim());
		}
		if (!symbols.isEmpty()) {
			stringUrl = YahooRealTimeQuoteLoader.makeQuoteURLString(new ArrayList<String>(symbols));
			Vector<String> results = YahooRealTimeQuoteLoader.getUrlVector(stringUrl);
			if (!results.isEmpty()) {
				for(String string : results) {
					quoteRTListed = new QuoteRTListed(string);
					if (quoteRTListed!=null) {
						log.info(quoteRTListed.getSymbolId()+": last="+quoteRTListed.getLast().toString());
						quoteMap.put(quoteRTListed.getSymbolId(), quoteRTListed.getLast());
					}
				}
				
			}
		}
		//TODO add priceFormat handling here (should it be stored on the position?)
		if (!quoteMap.isEmpty()) {
			String symbol;
			Double quoteLast;
			Trade trade;
			Iterator<Position> iter2 = positions.iterator();
			while (iter2.hasNext()) {
				position = iter2.next();
				// handle cash
				if (position.getCashPosition()) {
					// transaction related transaction 
					if (position.getStageType()==StageType.TRANSACTION ||
						position.getTradeKey()==null) {
						position.setMarketValue(position.getQuantity());
						position.setExposureValue(position.getExposureValue());
					} else {
						// order/simulation related
						// Go to original trade and value using the latest price to calculate the
						// current cash value
						try {
							trade = new Trade(ds.get(position.getTradeKey()));
							symbol = "\""+trade.getSymbolKey().getName()+"\"";
							quoteLast = quoteMap.get(symbol);
							if (quoteLast.isNaN()) {
								position.setMarketValue(position.getQuantity());
								position.setExposureValue(position.getExposureValue());
							} else {
								position.setQuantity(-trade.getQuantity()*quoteLast);
								position.setMarketValue(position.getQuantity());
								position.setExposureValue(position.getQuantity());
							}
							log.info(position.toString());
						} catch (EntityNotFoundException ex) {
							// TODO Auto-generated catch block
							ex.printStackTrace();
						}
					}
				} else {
					symbol = "\""+position.getSymbolKey().getName()+"\"";
					quoteLast = quoteMap.get(symbol);
					if (quoteLast != null) {
						if (position.getPriceFormat()!=PriceFormat.SIMPLE)
							quoteLast /= 100;
						position.setMarketValue(position.getQuantity()*quoteLast);
					} else {
						// use Trade
						try {
							trade = new Trade(ds.get(position.getTradeKey()));
							position.setMarketValue(trade.getPrincipalAmount());
						} catch (EntityNotFoundException ex) {
							// TODO Auto-generated catch block
							ex.printStackTrace();
						}
					}
					position.setExposureValue(position.getMarketValue());
					log.info(position.toString());
				}
			}
			
		}
	}
	
	private void listByTradeId(Key accountKey, Long tradeId) {

		FetchOptions fo = FetchOptions.Builder.withDefaults();

		List<Entity> trades = new ArrayList<Entity>();
		
//		Filter tradeExpirationFilter = 
//				new FilterPredicate("expirationTimestamp",FilterOperator.EQUAL,null);
//		Filter tradeStageTypeFilter = CompositeFilterOperator.or(
//					new FilterPredicate("stageType",FilterOperator.EQUAL,StageType.ORDER.name()),
//					new FilterPredicate("stageType",FilterOperator.EQUAL,StageType.EXECUTION.name()),
//					new FilterPredicate("stageType",FilterOperator.EQUAL,StageType.TRANSACTION.name()));
		Filter tradeIdFilter =
				new FilterPredicate("tradeId", FilterOperator.EQUAL,tradeId);
//		Filter notActiveFilter =
//				CompositeFilterOperator.and(tradeExpirationFilter,tradeIdFilter, tradeStageTypeFilter);
//		Filter notActiveFilter =
//				CompositeFilterOperator.and(tradeIdFilter, tradeStageTypeFilter);
//		Query q = new Query ("trade").setFilter(notActiveFilter)
		Query q = new Query ("trade").setFilter(tradeIdFilter)
				.setAncestor(accountKey)
				.addSort("effectiveTimestamp", SortDirection.DESCENDING);
		trades = ds.prepare(q).asList(fo);

		if (!trades.isEmpty()) {
			for (Entity entity : trades) {
				log.info(new Trade(entity).toString());
			}
		} else {
			System.err.println("No active trades found for tradeId="+tradeId+".");
		}
	}

}
